var TagCloud = {
  create: function() {
    return new TagCloud.Container();
  }
};

TagCloud.Http = function(){
  this.viewpointUri = null;
  this.viewpointName = null;
  this.topics = new Array();
  var pref = new Preferences(PREF_PREFIX);
  this.defaultService = pref.getPref("service", DEFAULT_SERVICE);
};

TagCloud.Http.prototype.retrieve = function(uri){

  var viewpoint = new Viewpoint();
  viewpoint.uri = uri;
  viewpoint = viewpoint.httpGet();
  if(viewpoint == null)
    return;
  this.viewpointUri = uri;
  this.viewpointName = viewpoint.name;

  for(var i=0; i < viewpoint.topics.length; i++)
    if((typeof viewpoint.topics[i].href) != "undefined" && viewpoint.topics[i].href != "")
      this.getTopic(viewpoint.topics[i].href);

  this.dump();
}

TagCloud.Http.prototype.getTopic = function(topicUri){
  var topic = new Topic();
  topic.uri = topicUri;
  topic = topic.httpGet();
  if(topic == null)
    return;
  var colorEntityPrefix = this.defaultService + COLORENTITY_PREFIX;
  var colorIndex = -1;
  for(var i =0; i < topic.entities.length; i++){
    var entity = topic.entities[i];
    debug("[tagcloud.js::getTopic] entity href:" + entity.href);
    if(entity.href.startsWith(colorEntityPrefix))
      try{
        colorIndex = parseInt(entity.href.substr(colorEntityPrefix.length,1));
      }catch(ex){ colorIndex = -1; }
  }
  debug("[tagcloud.js::getTopic] colorIndex:" + colorIndex);
  var result = new Array(topic.name, topic.uri, topic.entities.length, colorIndex);
  this.topics.push(result);
  for(var i=0; i < topic.relatedTopics.length; i++){
    rTopic = topic.relatedTopics[i];
    var found = false;
    for(var j=0; j < this.topics.length; j++)
      if(this.topics[j][1] == rTopic.href)
        found = true;
    if(found) continue;
    this.getTopic(rTopic.href);
  }
}

TagCloud.Http.prototype.dump = function(){
  for(var i=0; i < this.topics.length; i++){
    debug("topic["+i+"] name:" + this.topics[i][0] + ", uri:" + this.topics[i][1] + ", count:" + this.topics[i][2], 1);
  }
}

TagCloud.Tag = function (name, count, url, colorIndex) {
  this.name  = name;
  this.count = count;
  this.url   = url;
  this.colorIndex = colorIndex;
  this.style = {};
  this.initClasses();
  this.initAnchorClasses();
}

TagCloud.Tag.prototype.initClasses = function () {
  this.classes = ['tagcloud-base'];
}

TagCloud.Tag.prototype.initAnchorClasses = function () {
  this.anchorClasses = ['tagcloud-anchor'];
}

TagCloud.Tag.prototype.attachClass = function (className) {
  this.classes.push(className);
}

TagCloud.Tag.prototype.attachAnchorClass = function (className) {
  this.anchorClasses.push(className);
}

/*TagCloud.Tag.prototype.toElement = function() {
  var element = document.createElementNS(HTMLNS,'li');
  var linkElement = document.createElementNS(HTMLNS,'a');
  linkElement.setAttribute('uri', this.url);
  linkElement.setAttribute('href', '#');
  //linkElement.setAttribute('context', 'popupTag');
  var text = document.createTextNode(this.name);
  linkElement.appendChild(text);
  linkElement.className = this.anchorClasses.join(" ");
  element.appendChild(linkElement);
  element.className = this.classes.join(" ");
  for (var prop in this.style)
    element.style[prop] = this.style[prop];
  //debug("[Tag.toElement] element.innerHTML:" + element.innerHTML, 1);
  return element;
}*/

TagCloud.Tag.prototype.toElement = function() {
  var element = document.createElement('label');
  element.setAttribute('popup', 'popupTag');

  var linkElement = document.createElement('a');
  linkElement.setAttribute('uri', this.url);
  var text = document.createTextNode(this.name);
  linkElement.appendChild(text);
  linkElement.className = this.anchorClasses.join(" ");
  element.appendChild(linkElement);
  element.className = this.classes.join(" ");
  for (var prop in this.style)
    element.style[prop] = this.style[prop];
  return element;
}

TagCloud.Container = function () {
  this.reset();
  this.classes = {
    list: 'tagcloud-list'
  };
}

TagCloud.Container.prototype.reset = function () {
  this.tags      = new Array();
  this.effectors = new Array();
}

TagCloud.Container.prototype.clear = function () {
  this.tags = new Array();
}

TagCloud.Container.prototype.add = function (name, count, url, colorIndex) {
  if (count == 0)
    throw "TagCloud.Container.prototype.add: second argument should be over 0.";
  this.tags.push(this.createTag(name, count, url, colorIndex));
  //debug("[Container.add] tags length:" + this.tags.length,1);
}

TagCloud.Container.prototype.createTag = function (name, count, url, colorIndex) {
    return new TagCloud.Tag(name, count, url, colorIndex);
}

TagCloud.Container.prototype.toElement = function (filter) {
  var list = document.createElementNS(HTMLNS,'ul');
  for (var i = 0; i < this.tags.length; i++) {
    var tag = this.tags[i];
    if (!(filter && !filter(tag))) {

      list.appendChild(tag.toElement());
      list.appendChild(document.createTextNode("\n"));
    }
  }
  list.className = this.classes.list;
  //debug("[Container.toElement] list.innerHTML:" + list.innerHTML, 1);
  return list;
}

TagCloud.Container.prototype.setElementsTo = function (target) {
  //var target = document.getElementById(element);
  while (target.childNodes.length > 0)
    target.removeChild(target.firstChild);
  target.appendChild(this.toElement());
}

TagCloud.Container.prototype.searchAndDisplay = function (element, name) {
  var target = document.getElementById(element);
  while (target.childNodes.length > 0)
    target.removeChild(target.firstChild);
  var re = new RegExp(name, 'i');
  target.appendChild(this.toElement(function(tag){
    return tag.name.match(re);
  }));
}

TagCloud.Container.prototype.toHTML = function () {
  var temp = document.createElementNS(HTMLNS,'div');
  temp.appendChild(this.toElement());
  return temp.innerHTML;
}

TagCloud.Container.prototype.generateHTML = function () {
  this.runEffectors();
  return this.toHTML();
}

TagCloud.Container.prototype.setup = function (element) {
  this.runEffectors();
  this.setElementsTo(element);
}
TagCloud.Container.prototype.getContainer = function(uri,name){
  var parentContainer = document.getElementById("tagcloud_" + MD5(uri));
  //var parentContainer = document.getElementById('viewpointPanel');
  var panel = document.createElement("groupbox");
  panel.setAttribute("orient", "vertical");
  panel.className = "tagCloudPanel";
  panel.setAttribute("href", uri);
  var caption = document.createElement("caption");
  caption.setAttribute("label", name);
  panel.appendChild(caption);
  var container = document.createElementNS(HTMLNS, "div");
  //container.className = "noMargin";
  panel.appendChild(container);
  parentContainer.appendChild(panel);
  return container;
}
TagCloud.Container.prototype.clearTagCloud = function(uri){
  var container = document.getElementById("tagcloud_" + MD5(uri));
  while (container.hasChildNodes()) container.removeChild(container.firstChild);
  /*var vpPanels = document.getElementsByTagName('groupbox');
  for (var i = 0; i < vpPanels.length; i++) {
    var panel = vpPanels[i];
    var viewpointUrl = panel.getAttribute("href");
    if(viewpointUrl.length  == uri)
      return true;
  }
  return false;*/
}

TagCloud.Container.prototype.runEffectors = function () {
  for (var i = 0; i < this.effectors.length; i++) {
    var effector = this.effectors[i];
    effector.affect(this.tags);
  }
}

TagCloud.Container.prototype.loadEffector = function (effectorName) {
  var effectorClass = TagCloud.Effector[effectorName];
  if (!effectorClass)
    throw "Unknown Effector, " + effectorName;
  var effector = new effectorClass();
  this.effectors.push(effector);
  return effector;
}

TagCloud.Effector = new Object();

TagCloud.Effector.CountSize = function () {
  this.baseFontSize  = 24;
  this.fontSizeRange = 12;
  this._suffix       = "px";
  this.suffixTypes   = ['px', 'pt', 'pc', 'in', 'mm', 'cm'];
}

TagCloud.Effector.CountSize.prototype.base = function (size) {
  this.baseFontSize = size;
  return this;
}

TagCloud.Effector.CountSize.prototype.range = function (range) {
  this.fontSizeRange = range;
  return this;
}

TagCloud.Effector.CountSize.prototype.suffix = function (suffix) {
  for (var i = 0; i < this.suffixTypes.length; i++) {
    if (this.suffixTypes[i] == suffix) {
      this._suffix = suffix;
      break;
    }
  }
  return this;
}

TagCloud.Effector.CountSize.prototype.affect = function (tags) {
  var maxFontSize = this.baseFontSize + this.fontSizeRange;
  var minFontSize = this.baseFontSize - this.fontSizeRange;
  if (minFontSize < 0) minFontSize = 0;
  var range = maxFontSize - minFontSize;
  var min = null;
  var max = null;
  for (var i = 0; i < tags.length; i++) {
    var count = tags[i].count;
    if (min == null || min > count)
      min = count;
    if (max == null || max < count)
      max = count;
  }
  var calculator = new TagCloud.Calculator(min, max, range);
  for (var j = 0; j < tags.length; j++) {
    var tag  = tags[j];
    var size = calculator.calculate(tag.count);
    tag.style.fontSize = String(size + minFontSize) + this._suffix;
  }
}

TagCloud.Effector.HighLight = function() {
}

TagCloud.Effector.HighLight.prototype.setClass = function (classes) {
  for (var prop in classes) {
    this.styles[prop] = classes[prop];
  }
  return this;
}

TagCloud.Effector.HighLight.prototype.affect = function (tags) {
  for (var j = 0; j < tags.length; j++) {
    var tag  = tags[j];
    if(tag.colorIndex == -1)
      tag.style.color = "#000000";
    else
      tag.style.color = COLORS[tag.colorIndex];
    debug("[tagcloud.js::HighLight.affect] tag:" + dump(tag), 3);
    debug("[tagcloud.js::HighLight.affect] color:" + tag.style.color, 3);
  }
}

TagCloud.Calculator = function (min, max, range) {
  this.min    = Math.log(min);
  this.max    = Math.log(max);
  this.range  = range;
  this.factor = null;
  this.initializeFactor();
}

TagCloud.Calculator.prototype.initializeFactor = function() {
  if (this.min == this.max) {
    this.min -= this.range;
    this.factor = 1;
  } else {
    this.factor = this.range / (this.max - this.min);
  }
}

TagCloud.Calculator.prototype.calculate = function (num) {
  return parseInt((Math.log(num) - this.min) * this.factor);
}

function showTagCloud(uri){
  var tc = TagCloud.create();
  debug("[tagcloud.js::showTagCloud] open viewpoint (" + uri + ")",3);
  tc.clearTagCloud(uri);

  var http = new TagCloud.Http();
  http.retrieve(uri);
  debug("[tagcloud.js::showTagCloud] topics:" + dump(http.topics), 3);
  for(var i=0; i < http.topics.length; i++){
    var count = 1;
    try{ count = http.topics[i][2]; count++; }catch(ex){}
    tc.add(http.topics[i][0], count, http.topics[i][1], http.topics[i][3]);
  }
  tc.loadEffector('CountSize').base(14).range(5);
  tc.loadEffector('HighLight');
  var container = tc.getContainer(http.viewpointUri, http.viewpointName);
  tc.setup(container);
}